package shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import shiro.realm.MyRealm;

import java.util.Arrays;
import java.util.List;

// shiro用户认证代码
public class AuthenticatorTest {

    public static void main(String[] args) {

        /************************认证部分***********************/

        // 1.创建安全管理器
        DefaultSecurityManager securityManager = new DefaultSecurityManager();

        //2.获得realm设置密码加密
        MyRealm myRealm = new MyRealm();
        //设置realm使用hash凭证匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //声明：使用的算法
        credentialsMatcher.setHashAlgorithmName("md5");
        //声明：散列次数 ==>在加密时没有使用hash就不用写
        credentialsMatcher.setHashIterations(1024);
        // realm绑定加密算法
        myRealm.setCredentialsMatcher(credentialsMatcher);
        // 给安全管理器设置realm
        securityManager.setRealm(myRealm);

        //3.SecurityUtils给全局安全工具类设置安全管理器
        SecurityUtils.setSecurityManager(securityManager);

        //4.关键对象 subject主体
        Subject subject = SecurityUtils.getSubject();

        // 5.创建令牌
        // 登录界面传过来的账号,密码
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("wwj", "123");

        // 用户认证:返回值为void即,认证成功没有返回值,认证失败会抛出异常
        try {
            System.out.println("认证状态：" + subject.isAuthenticated());
            subject.login(usernamePasswordToken);
            System.out.println("认证状态：" + subject.isAuthenticated());
        } catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("认证失败，用户名不存在");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("认证失败，密码错误");
        }


        /************************授权部分***********************/
        if (subject.isAuthenticated()) { // 通过认证
            /********基于角色权限控制  MyRealm的doGetAuthorizationInfo()对应********/
            System.out.println("================基于角色权限控制================");
            // 判断是否具有admin角色
            System.out.println("判断是否具有admin角色:" + subject.hasRole("admin"));
            // 判断是否同时具有admin,user角色
            System.out.println("判断是否同时具有admin,user角色:" + subject.hasAllRoles(Arrays.asList("admin", "user")));
            // 分别具有哪些角色
            List<String> roleList = Arrays.asList("admin", "user", "xxx");
            boolean[] booleans = subject.hasRoles(roleList);
            for (int i = 0; i < roleList.size(); i++) {
                System.out.println("是否具有" + roleList.get(i) + "角色:" + booleans[i]);
            }

            /********基于权限字符串的访问控制  资源标识符：操作：资源类型  MyRealm的doGetAuthorizationInfo()对应********/
            System.out.println("================基于权限字符串的访问控制================");
            // 判断对user模块具的所有资源有所有权限
            System.out.println("对user模块具的所有资源有所有权限:" + subject.isPermitted("user:*:*"));
            // 判断是否同时具有 对user模块具的所有资源有所有权限 和 对product的02号资源有修改权限
            System.out.println("是否同时具有 对user模块具的所有资源有所有权限 和 对product的02号资源有修改权限:"
                    + subject.isPermittedAll("user:*:*", "product:update:02"));
            // 分别具有对user模块具的所有资源有所有权限 和 对product的02号资源有修改权限
            boolean[] permitted = subject.isPermitted("user:*:*", "product:update:02");
            System.out.println("是否具有user:*:*权限:" + permitted[0]);
            System.out.println("是否具有product:update:02权限:" + permitted[1]);

        }

    }

}
